<?php

if (!defined('ADODB_DIR'))
    die();

if (!defined('LDAP_ASSOC')) {
    define('LDAP_ASSOC', ADODB_FETCH_ASSOC);
    define('LDAP_NUM', ADODB_FETCH_NUM);
    define('LDAP_BOTH', ADODB_FETCH_BOTH);
}

class ADODB_ldap extends ADOConnection {

    var $databaseType = 'ldap';
    var $dataProvider = 'ldap';
    var $username = false;
    var $password = false;
    var $filter;
    var $dn;
    var $version;
    var $port = 389;
    var $LDAP_CONNECT_OPTIONS;
    var $_bind_errmsg = "Binding: %s";

    function ADODB_ldap() {
        
    }

    function _connect($host, $username, $password, $ldapbase) {
        global $LDAP_CONNECT_OPTIONS;

        if (!function_exists('ldap_connect'))
            return null;

        if (strpos($host, 'ldap://') === 0 || strpos($host, 'ldaps://') === 0) {
            $this->_connectionID = @ldap_connect($host);
        } else {
            $conn_info = array($host, $this->port);

            if (strstr($host, ':')) {
                $conn_info = explode(':', $host);
            }

            $this->_connectionID = @ldap_connect($conn_info[0], $conn_info[1]);
        }
        if (!$this->_connectionID) {
            $e = 'Could not connect to ' . $conn_info[0];
            $this->_errorMsg = $e;
            if ($this->debug)
                ADOConnection::outp($e);
            return false;
        }
        if (count($LDAP_CONNECT_OPTIONS) > 0) {
            $this->_inject_bind_options($LDAP_CONNECT_OPTIONS);
        }

        if ($username) {
            $bind = @ldap_bind($this->_connectionID, $username, $password);
        } else {
            $username = 'anonymous';
            $bind = @ldap_bind($this->_connectionID);
        }

        if (!$bind) {
            $e = sprintf($this->_bind_errmsg, ldap_error($this->_connectionID));
            $this->_errorMsg = $e;
            if ($this->debug)
                ADOConnection::outp($e);
            return false;
        }
        $this->_errorMsg = '';
        $this->database = $ldapbase;
        return $this->_connectionID;
    }

    function _inject_bind_options($options) {
        foreach ($options as $option) {
            ldap_set_option($this->_connectionID, $option["OPTION_NAME"], $option["OPTION_VALUE"])
                    or die("Unable to set server option: " . $option["OPTION_NAME"]);
        }
    }

    function _query($sql, $inputarr = false) {
        $rs = @ldap_search($this->_connectionID, $this->database, $sql);
        $this->_errorMsg = ($rs) ? '' : 'Search error on ' . $sql . ': ' . ldap_error($this->_connectionID);
        return $rs;
    }

    function ErrorMsg() {
        return $this->_errorMsg;
    }

    function ErrorNo() {
        return @ldap_errno($this->_connectionID);
    }

    function _close() {
        @ldap_close($this->_connectionID);
        $this->_connectionID = false;
    }

    function SelectDB($db) {
        $this->database = $db;
        return true;
    }

    function ServerInfo() {
        if (!empty($this->version))
            return $this->version;
        $version = array();
        ldap_get_option($this->_connectionID, LDAP_OPT_DEREF, $version['LDAP_OPT_DEREF']);
        switch ($version['LDAP_OPT_DEREF']) {
            case 0:
                $version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_NEVER';
            case 1:
                $version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_SEARCHING';
            case 2:
                $version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_FINDING';
            case 3:
                $version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_ALWAYS';
        }
        ldap_get_option($this->_connectionID, LDAP_OPT_SIZELIMIT, $version['LDAP_OPT_SIZELIMIT']);
        if ($version['LDAP_OPT_SIZELIMIT'] == 0) {
            $version['LDAP_OPT_SIZELIMIT'] = 'LDAP_NO_LIMIT';
        }
        ldap_get_option($this->_connectionID, LDAP_OPT_TIMELIMIT, $version['LDAP_OPT_TIMELIMIT']);
        if ($version['LDAP_OPT_TIMELIMIT'] == 0) {
            $version['LDAP_OPT_TIMELIMIT'] = 'LDAP_NO_LIMIT';
        }
        ldap_get_option($this->_connectionID, LDAP_OPT_REFERRALS, $version['LDAP_OPT_REFERRALS']);
        if ($version['LDAP_OPT_REFERRALS'] == 0) {
            $version['LDAP_OPT_REFERRALS'] = 'LDAP_OPT_OFF';
        } else {
            $version['LDAP_OPT_REFERRALS'] = 'LDAP_OPT_ON';
        }
        ldap_get_option($this->_connectionID, LDAP_OPT_RESTART, $version['LDAP_OPT_RESTART']);
        if ($version['LDAP_OPT_RESTART'] == 0) {
            $version['LDAP_OPT_RESTART'] = 'LDAP_OPT_OFF';
        } else {
            $version['LDAP_OPT_RESTART'] = 'LDAP_OPT_ON';
        }
        ldap_get_option($this->_connectionID, LDAP_OPT_PROTOCOL_VERSION, $version['LDAP_OPT_PROTOCOL_VERSION']);
        if ($version['LDAP_OPT_PROTOCOL_VERSION'] == 2) {
            $version['LDAP_OPT_PROTOCOL_VERSION'] = 'LDAP_VERSION2';
        } else {
            $version['LDAP_OPT_PROTOCOL_VERSION'] = 'LDAP_VERSION3';
        }
        ldap_get_option($this->_connectionID, LDAP_OPT_HOST_NAME, $version['LDAP_OPT_HOST_NAME']);
        ldap_get_option($this->_connectionID, LDAP_OPT_ERROR_NUMBER, $version['LDAP_OPT_ERROR_NUMBER']);
        ldap_get_option($this->_connectionID, LDAP_OPT_ERROR_STRING, $version['LDAP_OPT_ERROR_STRING']);
        ldap_get_option($this->_connectionID, LDAP_OPT_MATCHED_DN, $version['LDAP_OPT_MATCHED_DN']);

        return $this->version = $version;
    }

}

class ADORecordSet_ldap extends ADORecordSet {

    var $databaseType = "ldap";
    var $canSeek = false;
    var $_entryID;

    function ADORecordSet_ldap($queryID, $mode = false) {
        if ($mode === false) {
            global $ADODB_FETCH_MODE;
            $mode = $ADODB_FETCH_MODE;
        }
        switch ($mode) {
            case ADODB_FETCH_NUM:
                $this->fetchMode = LDAP_NUM;
                break;
            case ADODB_FETCH_ASSOC:
                $this->fetchMode = LDAP_ASSOC;
                break;
            case ADODB_FETCH_DEFAULT:
            case ADODB_FETCH_BOTH:
            default:
                $this->fetchMode = LDAP_BOTH;
                break;
        }

        $this->ADORecordSet($queryID);
    }

    function _initrs() {
        $this->_numOfRows = ldap_count_entries($this->connection->_connectionID, $this->_queryID);
    }

    function GetAssoc($force_array = false, $first2cols = false) {
        $records = $this->_numOfRows;
        $results = array();
        for ($i = 0; $i < $records; $i++) {
            foreach ($this->fields as $k => $v) {
                if (is_array($v)) {
                    if ($v['count'] == 1) {
                        $results[$i][$k] = $v[0];
                    } else {
                        array_shift($v);
                        $results[$i][$k] = $v;
                    }
                }
            }
        }

        return $results;
    }

    function GetRowAssoc() {
        $results = array();
        foreach ($this->fields as $k => $v) {
            if (is_array($v)) {
                if ($v['count'] == 1) {
                    $results[$k] = $v[0];
                } else {
                    array_shift($v);
                    $results[$k] = $v;
                }
            }
        }

        return $results;
    }

    function GetRowNums() {
        $results = array();
        foreach ($this->fields as $k => $v) {
            static $i = 0;
            if (is_array($v)) {
                if ($v['count'] == 1) {
                    $results[$i] = $v[0];
                } else {
                    array_shift($v);
                    $results[$i] = $v;
                }
                $i++;
            }
        }
        return $results;
    }

    function _fetch() {
        if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0)
            return false;

        if ($this->_currentRow == 0) {
            $this->_entryID = ldap_first_entry($this->connection->_connectionID, $this->_queryID);
        } else {
            $this->_entryID = ldap_next_entry($this->connection->_connectionID, $this->_entryID);
        }

        $this->fields = ldap_get_attributes($this->connection->_connectionID, $this->_entryID);
        $this->_numOfFields = $this->fields['count'];
        switch ($this->fetchMode) {

            case LDAP_ASSOC:
                $this->fields = $this->GetRowAssoc();
                break;

            case LDAP_NUM:
                $this->fields = array_merge($this->GetRowNums(), $this->GetRowAssoc());
                break;

            case LDAP_BOTH:
            default:
                $this->fields = $this->GetRowNums();
                break;
        }
        return ( is_array($this->fields) );
    }

    function _close() {
        @ldap_free_result($this->_queryID);
        $this->_queryID = false;
    }

}

?>